﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Security.AccessControl;
using System.Windows.Forms;
using Microsoft.Win32;

namespace KillingTrashFromExplorer
{
    public partial class MainWindow : Form
    {
        #region Dictionaries
        private readonly Dictionary<string, string> _path = new Dictionary<string, string>()
                                                                {
                                                                    {
                                                                        "Favorites",
                                                                        "{323CA680-C24D-4099-B94D-446DD2D7249E}"
                                                                        },
                                                                    {
                                                                        "HomeGroup",
                                                                        "{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}"
                                                                        },
                                                                    {
                                                                        "Libraries",
                                                                        "{031E4825-7B94-4dc3-B131-E946B44C8DD5}"
                                                                        },
                                                                    {"Net", "{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}"},
                                                                    {
                                                                        "UserFolder",
                                                                        "{59031a47-3f72-44a7-89c5-5595fe6b30ee}"
                                                                        },
                                                                };

        private readonly Dictionary<string, uint> _enabledValues = new Dictionary<string, uint>()
                                                                       {
                                                                           {"Favorites", 0xa0900100},
                                                                           {"HomeGroup", 0xb084010c},
                                                                           {"Libraries", 0xb080010d},
                                                                           {"Net", 0xb0040064},
                                                                           {"UserFolder", 0xf084012d},
                                                                       };

        private readonly Dictionary<string, uint> _disablesValues = new Dictionary<string, uint>()
                                                                        {

                                                                            {"Favorites", 0xa9400100},
                                                                            {"HomeGroup", 0xb094010c},
                                                                            {"Libraries", 0xb090010d},
                                                                            {"Net", 0xb0940064},
                                                                            {"UserFolder", 0xf094012d},
                                                                        };

        

        private Dictionary<string, CheckBox> _checkBoxes = new Dictionary<string, CheckBox>();
        private void Fill_checkBoxes()
        {
            _checkBoxes.Add("Favorites",checkBoxFavorites);
            _checkBoxes.Add("HomeGroup", checkBoxHomeGroup);
            _checkBoxes.Add("Libraries", checkBoxLibraries);
            _checkBoxes.Add("Net", checkBoxNet);
            _checkBoxes.Add("UserFolder", checkBoxUserFolder);
        }


                                                               
        #endregion
        private int _gettingAccessTriesCount = 0;


        public MainWindow()
        {
            InitializeComponent();
            Closing += new CancelEventHandler(MainWindow_Closing);
            
        }

        void MainWindow_Closing(object sender, CancelEventArgs e)
        {
            DeleteTempFiles();
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {
            _checkingOSVersion();
            Fill_checkBoxes();
            try
            {
                OnLoadChecking();
            }
            catch (Exception ex)
            {
                string message = string.Format("An exception occurs while checking registry.\n\n"+
                    "Message: {0}.\n"+
                    "It is well known error, but there is no any solutions for it now.\n\n"+
                    "The remaining part of program should work properly. Sorry.",ex.Message);
                MessageBox.Show(message,"Ups",MessageBoxButtons.OK,MessageBoxIcon.Information);
            }
            
            this.checkBoxUserFolder.CheckedChanged += new System.EventHandler(this.checkBoxCurrUser_CheckedChanged);
            this.checkBoxNet.CheckedChanged += new System.EventHandler(this.checkBoxNet_CheckedChanged);
            this.checkBoxLibraries.CheckedChanged += new System.EventHandler(this.checkBoxLibraries_CheckedChanged);
            this.checkBoxHomeGroup.CheckedChanged += new System.EventHandler(this.checkBoxHomeGroup_CheckedChanged);
            this.checkBoxFavorites.CheckedChanged += new System.EventHandler(this.checkBoxFavorites_CheckedChanged);
        }

        private void btnExit_Click(object sender, EventArgs e)
        {
            DeleteTempFiles();
            if (
                MessageBox.Show("Changes will be seen after computer restart\n\n\tRestart now?", "Closing",
                                MessageBoxButtons.YesNo, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1) ==
                DialogResult.Yes)
            {
                Process.Start("shutdown.exe", "-r -f -t 00");
            }
            Application.Exit();
        }
        static long IntToLong(int value)
        {
            return ((long)value) & 0xFFFFFFFFL;
        }

        //The very problematic method. Works only on the first program running.
        //On my mind it comes from changes  initial (Dword) values in Registry to new (Qword) 
        //(because I can't set hex values (e.g. 0xa0900100) in Dword (int32) format)
        //Thus, marshaling (int) key.GetValue("Attributes") don't work properly.
        private void OnLoadChecking()
        {
            
            foreach (KeyValuePair<string, string> pair in _path)
            {
                string path = string.Format(@"Software\Classes\CLSID\{0}\ShellFolder", pair.Value);
                RegistryKey key = Registry.LocalMachine.OpenSubKey(path, RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey);
                if (IntToLong((int) key.GetValue("Attributes")) == _enabledValues[pair.Key])
                {
                    _checkBoxes[pair.Key].Checked=true;
                }
                else
                {
                    _checkBoxes[pair.Key].Checked = false;
                }
            }
        }

        private void _checkingOSVersion()
        {
            OperatingSystem osInfo = Environment.OSVersion;
            if (osInfo.Version.Major == 6)
            {
                if (OSBitness.Is64BitOperatingSystem())
                {
                    LabelOSVersion.Text = "Windows 7 x64";
                    return;
                }
                else
                {
                    LabelOSVersion.Text = "Windows 7 x32";
                    return;
                }
            }
            MessageBox.Show("Working on Win7 only", "Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
            Application.Exit();
        }
        
        #region CheckBox CheckedChanged

        private bool ChangeCheckboxState(bool currentState)
        {
            if (currentState) return false;
            else return true;
        }

        private void checkBoxFavorites_CheckedChanged(object sender, EventArgs e)
        {
            ((CheckBox)sender).CheckedChanged -= checkBoxFavorites_CheckedChanged;
            string Member = "Favorites";

            if (CheckBoxProcessing(Member, checkBoxFavorites.Checked))
            {
                labelFavorites.ForeColor = checkBoxFavorites.Checked ? Color.Red : Color.Green;
                labelFavorites.Text = checkBoxFavorites.Checked ? "On" : "Off";
            }
            else
            {
                checkBoxFavorites.Checked = ChangeCheckboxState(checkBoxFavorites.Checked);
            }
            ((CheckBox)sender).CheckedChanged += checkBoxFavorites_CheckedChanged;

        }

        private void checkBoxHomeGroup_CheckedChanged(object sender, EventArgs e)
        {
            ((CheckBox)sender).CheckedChanged -= checkBoxHomeGroup_CheckedChanged;
            string Member = "HomeGroup";
            if (CheckBoxProcessing(Member, checkBoxHomeGroup.Checked))
            {
                labelHomeGroup.ForeColor = checkBoxHomeGroup.Checked ? Color.Red : Color.Green;
                labelHomeGroup.Text = checkBoxHomeGroup.Checked ? "On" : "Off";
            }
            else
            {
                checkBoxHomeGroup.Checked = ChangeCheckboxState(checkBoxHomeGroup.Checked);
            }
            ((CheckBox) sender).CheckedChanged += checkBoxHomeGroup_CheckedChanged;
        }

        private void checkBoxLibraries_CheckedChanged(object sender, EventArgs e)
        {
            ((CheckBox)sender).CheckedChanged -= checkBoxLibraries_CheckedChanged;
            string Member = "Libraries";
            if (CheckBoxProcessing(Member, checkBoxLibraries.Checked))
            {
                labelLibraries.ForeColor = checkBoxLibraries.Checked ? Color.Red : Color.Green;
                labelLibraries.Text = checkBoxLibraries.Checked ? "On" : "Off";
            }
            else
            {
                checkBoxLibraries.Checked = ChangeCheckboxState(checkBoxLibraries.Checked);
            }
            ((CheckBox)sender).CheckedChanged += checkBoxLibraries_CheckedChanged;
        }

        private void checkBoxNet_CheckedChanged(object sender, EventArgs e)
        {
            ((CheckBox)sender).CheckedChanged -= checkBoxNet_CheckedChanged;
            string Member = "Net";
            if (CheckBoxProcessing(Member, checkBoxNet.Checked))
            {
                labelNet.ForeColor = checkBoxNet.Checked ? Color.Red : Color.Green;
                labelNet.Text = checkBoxNet.Checked ? "On" : "Off";
            }
            else
            {
                checkBoxNet.Checked = ChangeCheckboxState(checkBoxNet.Checked);
            }
            ((CheckBox)sender).CheckedChanged += checkBoxNet_CheckedChanged;
        }

        private void checkBoxCurrUser_CheckedChanged(object sender, EventArgs e)
        {
            ((CheckBox)sender).CheckedChanged -= checkBoxCurrUser_CheckedChanged;
            string Member = "UserFolder";
            if (CheckBoxProcessing(Member, checkBoxUserFolder.Checked))
            {
                labelUserFolder.ForeColor = checkBoxUserFolder.Checked ? Color.Red : Color.Green;
                labelUserFolder.Text = checkBoxUserFolder.Checked ? "On" : "Off";
            }
            else
            {
                checkBoxUserFolder.Checked = ChangeCheckboxState(checkBoxUserFolder.Checked);
            }
            ((CheckBox)sender).CheckedChanged += checkBoxCurrUser_CheckedChanged;
        }

        #endregion

        private bool CheckBoxProcessing(string member, bool isChecked)
        {
            try
            {
                string path = string.Format(@"Software\Classes\CLSID\{0}\ShellFolder", _path[member]);
                using (RegistryKey key = Registry.LocalMachine.OpenSubKey(path,
                                                                          RegistryKeyPermissionCheck.ReadWriteSubTree,
                                                                          RegistryRights.FullControl))
                {
                    key.SetValue("Attributes", isChecked ? _enabledValues[member] : _disablesValues[member],
                                 RegistryValueKind.QWord);
                    key.Flush();
                }
                if (OSBitness.Is64BitOperatingSystem())
                {
                    path = string.Format(@"Software\Wow6432Node\Classes\CLSID\{0}\ShellFolder", _path[member]);
                    using (RegistryKey key = Registry.LocalMachine.OpenSubKey(path,
                                                                              RegistryKeyPermissionCheck.
                                                                                  ReadWriteSubTree,
                                                                              RegistryRights.FullControl))
                    {
                        //key.SetAccessControl(rs);
                        key.SetValue("Attributes", isChecked ? _enabledValues[member] : _disablesValues[member],
                                     RegistryValueKind.QWord);
                        key.Flush();
                    }
                }
            }
            catch (Exception ex)
            {
                _gettingAccessTriesCount += 1;
                if (_gettingAccessTriesCount<=2)
                {
                    if (
                    (MessageBox.Show(string.Format("Exception message:{0}\n\nTry to get permissions?", ex.Message),
                                     "Error", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes))
                    {

                        SetFullAccessToNeededRegistryHeeves();
                    }
                    else
                    {
                        ExitingMessage();
                    }
                }
                else
                {
                    ExitingMessage();
                }
                ;
                return false;
            }
            return true;
        }
        void ExitingMessage()
        {
            MessageBox.Show(
                        "Can't process without neccessary permissions\nCall your administrator for more information",
                        "Sorry application will be closed.");
            Application.Exit();
        }

        private void SetFullAccessToNeededRegistryHeeves()
        {
            Stream file;
            try
            {
                Directory.CreateDirectory(Environment.ExpandEnvironmentVariables("%TEMP%"));
                file = File.Create(Environment.ExpandEnvironmentVariables(@"%TEMP%\Perm.txt"));
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    string.Format("While creating temp folder or inner file, got exception:\n{0}", ex.Message), "Error");
                return;
            }
            StreamWriter sw = new StreamWriter(file);
            sw.WriteLine(
                @"\Registry\Machine\Software\Classes\CLSID\{323CA680-C24D-4099-B94D-446DD2D7249E}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Classes\CLSID\{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Classes\CLSID\{031E4825-7B94-4dc3-B131-E946B44C8DD5}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Classes\CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Classes\CLSID\{59031a47-3f72-44a7-89c5-5595fe6b30ee}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Wow6432Node\Classes\CLSID\{323CA680-C24D-4099-B94D-446DD2D7249E}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Wow6432Node\Classes\CLSID\{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Wow6432Node\Classes\CLSID\{031E4825-7B94-4dc3-B131-E946B44C8DD5}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Wow6432Node\Classes\CLSID\{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Wow6432Node\Classes\CLSID\{59031a47-3f72-44a7-89c5-5595fe6b30ee}\ShellFolder [1 5 7 17]");
            sw.WriteLine(
                @"\Registry\Machine\Software\Wow6432Node\Classes\CLSID\{59031a47-3f72-44a7-89c5-5595fe6b30ee}\ShellFolder [1 5 7 17]");
            sw.Close();
            Process.Start("regini.exe",Environment.ExpandEnvironmentVariables(@"%TEMP%\Perm.txt"));
        }
        
        private void DeleteTempFiles()
        {
            try
            {
                if (File.Exists(Environment.ExpandEnvironmentVariables(@"%TEMP%\Perm.txt")))
                    File.Delete(Environment.ExpandEnvironmentVariables(@"%TEMP%\Perm.txt"));
                if (File.Exists(Environment.ExpandEnvironmentVariables(@"%TEMP%\regini.exe")))
                    File.Delete(Environment.ExpandEnvironmentVariables(@"%TEMP%\regini.exe"));
            }
            catch (Exception)
            {
                
                throw;
            }
            
        }

        
    }

    
}
